package suncertify.service.remote;

import suncertify.db.*;

import java.rmi.RemoteException;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;

/**
 * Implementation of RemoteData interface
 */
public class RemoteDataImpl implements RemoteData {
    private Data data;
    private long currClientId = 0;
    private final Map<Long, Session> sessions = new HashMap<Long, Session>();

    private class Session {
        Map<Integer, Thread> lockingThreads = new HashMap<Integer, Thread>();
    }

    public RemoteDataImpl(String dataFile) throws IOException {
        data = new Data(dataFile);
    }

    public String[] read(int recNo) throws RecordNotFoundException {
        return data.read(recNo);
    }

    public void update(int recNo, String[] data, long lockCookie) throws RecordNotFoundException {
        this.data.update(recNo, data, lockCookie);
    }

    public void delete(int recNo, long lockCookie) throws RecordNotFoundException {
        data.delete(recNo, lockCookie);
    }

    public int[] find(String[] criteria) {
        return data.find(criteria);
    }

    public int create(String[] data) throws DuplicateKeyException {
        return this.data.create(data);
    }

    public long lock(int id, long clientId) throws RecordNotFoundException {
        long lock;
        Session s = sessions.get(clientId);
        try {
            s.lockingThreads.put(id, Thread.currentThread());
            lock = data.lock(id);
        } finally {
            s.lockingThreads.remove(id);
        }
        return lock;
    }

    public void unlock(int recNo, long cookie) throws RecordNotFoundException {
        data.unlock(recNo, cookie);
    }

    public String getColumnName(int col) throws RemoteException {
        return data.getColumnName(col);
    }

    public int getColumnCount() throws RemoteException {
        return data.getColumnCount();
    }

    public void cancelLocking(Integer id, Long clientId) throws RemoteException {
        Thread t = sessions.get(clientId).lockingThreads.get(id);
        if (t != null && t.isAlive()) {
            t.interrupt();
        }
    }

    public long getRemoteClientId() throws RemoteException {
        return currClientId = (currClientId % (Long.MAX_VALUE - 1)) + 1;
    }

    public void startSession(long clientId) {
        sessions.put(clientId, new Session());
    }

    public void closeSession(long clientId) {
        Session s = sessions.get(clientId);
        if (s == null) {
            return;
        }
        for (Thread t : s.lockingThreads.values()) {
            if (t != null && t.isAlive()) {
                t.interrupt();
            }
        }
    }
}
